home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
gamesrc
/
arasan_s
/
scoring.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-07
|
31KB
|
1,087 lines
// Copyright 1994 by Jon Dart. All Rights Reserved.
#include "scoring.h"
#include "bearing.h"
#include "constant.h"
#include "util.h"
static int RookCenterTable[] =
{0, 0, 0, 27, 28, 0, 0, 0,
0, 0, 0, 27, 28, 0, 0, 0,
0, 0, 0, 27, 28, 0, 0, 0,
27, 27, 27, 27, 28, 28, 28, 28,
35, 35, 35, 35, 36, 36, 36, 36,
0, 0, 0, 35, 36, 0, 0, 0,
0, 0, 0, 35, 36, 0, 0, 0,
0, 0, 0, 35, 36, 0, 0, 0};
static int RookCenterDirs[] =
{0, 0, 0, 8, 8, 0, 0, 0,
0, 0, 0, 8, 8, 0, 0, 0,
0, 0, 0, 8, 8, 0, 0, 0,
1, 1, 1, 0, 0, -1, -1, -1,
1, 1, 1, 0, 0, -1, -1, -1,
0, 0, 0, -8, -8, 0, 0, 0,
0, 0, 0, -8, -8, 0, 0, 0,
0, 0, 0, -8, -8, 0, 0, 0};
static int BishopCenterTable[] =
{27, 28, 0, 0, 0, 0, 27, 28,
35, 27, 28, 0, 0, 27, 28, 36,
0, 35, 27, 28, 27, 28, 36, 0,
0, 0, 35, 27, 28, 36, 0, 0,
0, 0, 27, 28, 36, 28, 0, 0,
0, 27, 35, 36, 35, 36, 28, 0,
27, 35, 36, 0, 0, 35, 36, 28,
35, 36, 0, 0, 0, 0, 35, 36};
static int BishopCenterDirs[] =
{9, 9, 0, 0, 0, 0, 7, 7,
9, 9, 9, 0, 0, 7, 7, 7,
0, 9, 9, 9, 7, 7, 7, 0,
0, 0, 9, 0, 0, 7, 0, 0,
0, 0, -7, 0, 0, -9, 0, 0,
0, -7, -7, -7, -9, -9, -9, 0,
-7, -7, -7, 0, 0, -9, -9, -9,
-7, -7, 0, 0, 0, 0, -9, -9};
static int KnightCenterScores[] =
{0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 2, 0, 0,
0, 2, 0, 0, 0, 0, 2, 0,
0, 2, 0, 5, 5, 0, 2, 0,
0, 2, 0, 5, 5, 0, 2, 0,
0, 2, 0, 0, 0, 0, 2, 0,
0, 0, 2, 2, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
static int PawnCenterScores[] =
{0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 5, 5, 0, 0, 0,
0, 0, 4, 6, 6, 4, 0, 0,
0, 0, 3, 4, 4, 3, 0, 0,
0, 0, -1, -2, -2, -1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
static int KingCenterScores[] =
{0, 0, 1, 1, 1, 1, 0, 0,
0, 1, 2, 3, 3, 2, 1, 0,
1, 2, 6, 7, 7, 6, 2, 1,
1, 3, 7, 9, 9, 7, 3, 1,
1, 3, 7, 9, 9, 7, 3, 1,
1, 2, 6, 7, 7, 6, 2, 1,
0, 1, 2, 3, 3, 2, 1, 0,
0, 0, 1, 1, 1, 1, 0, 0};
const int KBNKScores[] =
{-12, -8, -2, 3, 7, 10, 15, 20,
-8, -6, 1, 0, 5, 9, 12, 15,
-2, 1, 0, 0, 5, 8, 9, 10,
3, 2, 0, 0, 0, 5, 5, 7,
7, 5, 5, 0, 0, 0, 0, 3,
10, 9, 8, 5, 0, 0, 1, -2,
15, 12, 9, 5, 2, 1, -6, -8,
20, 15, 10, 7, 3, -2, -8, -12};
Boolean Scoring::pawn_threats = False;
int Scoring::en_prise = 0;
int Scoring::trapped = 0;
static Boolean endgame;
static int distance( const Square sq1, const Square sq2 )
{
int file_dist = Util::Abs(sq1.File() - sq2.File());
int rank_dist = Util::Abs(sq1.Rank(White) - sq2.Rank(White));
return file_dist + rank_dist;
}
// Weights for positional scoring components. A plus value means that
// the item being scored is valuable to the player; a minus value means
// that a penalty is extracted. In most cases, scoring components are
// simply summed together to get a total score, but some are folded
// in, in a more complex way.
// material terms
const int TWO_BISHOPS = 8;
// development terms
const int CENTER1 = 2; // center control by sliding piece
const int BLOCKED_BISHOP = -4;
const int LOW_BISHOP_MOBILITY = -2;
const int BMOBLTHRESH = 3; // threshold before awarding bishop mobility bonus
const int BISHOP_MOBILITY = 2;
const int BISHOP_BACK = -6;
const int CENTER_PAWN_BLOCK = -5; // e or d pawn blocked by piece
const int LONG_DIAG = 3; // bishop on long diagonal
const int KNIGHT_BACK = -5;
const int KNIGHT_ON_RIM = -2;
const int LOW_ROOK_MOBILITY = -1;
const int KNIGHT_MOBILITY = 1;
const int ROOK_ON_7TH_RANK = 5;
const int QUEEN_DEVELOP = 2;
const int QUEEN_OUT = -6; // premature development of queen
const int DOUBLED_ROOKS = 6; // on open file
const int ROOK_ON_HALF_OPEN_FILE = 2;
const int ROOK_ON_OPEN_FILE = 2;
// castling terms
const int KCASTLE = 9;
const int QCASTLE = 6;
const int CAN_CASTLE = -2;
const int CANT_CASTLE = -12;
const int CANT_CASTLE_K_SIDE = -6;
const int CANT_CASTLE_Q_SIDE = -4;
const int ATTACK_PREVENTS_CASTLING = -3;
// pawn structure terms
const int PAWN_ON_7TH_RANK = 4;
const int BACKWARD_PAWN = -6;
const int CENTRAL_ISOLANI = -8;
const int ISOLANI = -6;
const int DOUBLED_PAWNS = -18;
const int TRIPLED_PAWNS = -24;
const int PASSED_PAWN[8] = { 0, 12, 13, 17, 25, 41, 73, 0}; // score by rank
const int RIM_PASSED_PAWN = -3; // pawn on h-file or a-file
const int PAWN_DUO = 4; // a la Kmoch
const int ROOK_BEHIND_PP = 3; // rook or queen behind passed pawn
const int UNSUPPORTED_PAWN = -1; // an advanced but unsupported pawn
const int OPP_KING_DISTANCE_FROM_PP = 2; // opposing king distance from passed
// pawn
const int OPP_KING_AHEAD_OF_PP = -7;
// king safety terms
const int CHECK = -5; // being in check
const int ATTACK_NEAR_KING = -3; // square near king attacked
const int KING_OFF_BACK_RANK = -3;
const int KING_PAWN_COVER = 2;
const int KING_NEAR_OPEN_FILE = -1;
const int DANGER_ON_FILE = -2; // rook or queen on file near king
// king position terms - valid only in endgame
const int ADVANCED_KING = 4;
const int KING_NEAR_PAWN = 1;
const int OPPOSITION = 12;
const int KING_DISTANCE = 4; // bringing our king closer to bare king
const int KING_CAN_MOVE = -3; // for each square opposing bare king can move
const int KING_ON_EDGE = 4; // opposing king on edge
const int KING_IN_CORNER = 4; // opposing king in corner
// piece safety terms
const int EN_PRISE = -6; // piece apparently hung
const int PIECE_TRAPPED = -6; // piece apparently trapped
const int TWO_EN_PRISE = -10; // >1 piece apparently hung
// general endgame terms
const int KING_PAWN_DISTANCE = -10; // distance from opposing king
const int OPP_KING_AHEAD_OF_PAWN = 8;
// KP vs. K endgame
const int UNCATCHABLE_PAWN = 450;
const int KING_AHEAD_OF_PAWN = 32;
const int KING_SAME_FILE = 32;
const int DISTANCE_FROM_PAWN = -8;
static int MaterialScore( const Board &board, const ColorType side )
{
// Computes material score, from the perspective of 'side'.
// Algorithm is based on that used by Chess 4.5.
unsigned long ourmat, oppmat, totmat;
int mdiff;
ourmat = board.getMaterial(side).value();
oppmat = board.getMaterial(OppositeColor(side)).value();
mdiff = (int)(ourmat - oppmat);
if (Util::Abs(mdiff) > 2*Constants::PawnValue)
{
totmat = ourmat + oppmat;
return mdiff + (Util::Sign(mdiff)*( (10240L - totmat) /
Constants::PawnValue ));
}
else
return mdiff;
}
static Boolean in_endgame( const Board &board, const ColorType side )
{
return Boolean((board.getMaterial(side).value()
<= Piece::Value(Piece::King) +
Piece::Value(Piece::Queen)) &&
(board.getMaterial(OppositeColor(side)).value() <=
Piece::Value(Piece::King) + Piece::Value(Piece::Queen) +
2*Piece::Value(Piece::Pawn)));
}
static Boolean mopping_up( const Board &board, const ColorType side )
{
// Returns "true" if "side" has great material advantage (probably
// enough to mate by force)
const Material &my_mat = board.getMaterial(side);
const Material &opp_mat = board.getMaterial(OppositeColor(side));
if (opp_mat.king_only() && !endgame)
return True;
else if (my_mat.value() - opp_mat.value() < 570)
return False;
else
return (my_mat.value() + opp_mat.value() < 5000);
}
int Center( const Board &board, const ColorType side)
{
if (endgame)
{
if (mopping_up(board,OppositeColor(side)))
return KingCenterScores[board.KingPos(side)];
else
return 0;
}
int score = 0;
Square target;
for (int i = 0; i < 16; i++)
{
Square sq(board.PiecePos(side,i));
if (!sq.IsInvalid())
{
Piece piece = board[sq];
switch (piece.Type())
{
case Piece::Pawn:
if (side == White)
score += PawnCenterScores[sq];
else
score += PawnCenterScores[63-(int)sq];
break;
case Piece::Knight:
score += KnightCenterScores[sq];
break;
case Piece::Bishop:
target = Square(BishopCenterTable[sq]);
if (target)
{
int dir = BishopCenterDirs[sq];
if (dir)
{
for (;;)
{
sq += dir;
if (sq == target)
{
score += CENTER1;
break;
}
else if (!board[sq].IsEmpty())
break;
}
}
else
score += CENTER1;
}
break;
case Piece::Rook:
target = Square(RookCenterTable[sq]);
if (target)
{
int dir = RookCenterDirs[sq];
if (dir)
{
for (;;)
{
sq += dir;
if (sq == target)
{
score += CENTER1;
break;
}
else if (!board[sq].IsEmpty())
break;
}
}
else
score += CENTER1;
}
break;
case Piece::Queen:
target = Square(BishopCenterTable[sq]);
if (target)
{
int dir = BishopCenterDirs[sq];
if (dir)
{
for (;;)
{
sq += dir;
if (sq == target)
{
score += CENTER1;
break;
}
else if (!board[sq].IsEmpty())
break;
}
}
else
score += CENTER1;
}
target = Square(RookCenterTable[sq]);
if (target)
{
int dir = RookCenterDirs[sq];
if (dir)
{
for (;;)
{
sq += dir;
if (sq == target)
{
score += CENTER1;
break;
}
else if (!board[sq].IsEmpty())
break;
}
}
else
score += CENTER1;
}
break;
default:
break;
}
}
}
return score;
}
int Development( const Board &board, const ColorType side)
// development of pieces
{
int score = 0;
int score2 = 0;
int mobl = 0;
Boolean have_queen = False;
Boolean queen_back = False;
const ColorType oside = OppositeColor(side);
const Material &my_mat = board.getMaterial(side);
if (my_mat.count(Piece::Bishop) >= 2)
score += TWO_BISHOPS;
for (int i = 0; i < 16; i++)
{
Square sq(board.PiecePos(side,i));
if (!sq.IsInvalid())
{
Piece piece = board[sq];
if (piece.Type() != Piece::Pawn)
{
const int rank = sq.Rank(side);
const int file = sq.File();
Boolean back = Boolean(rank == 1);
if (!endgame)
{
if ((rank == 3 || rank == 4) &&
(file == 4 || file == 5))
{
int incr = 8*Direction[side];
if (board[sq-incr].Type() == Piece::Pawn ||
board[sq-2*incr].Type() == Piece::Pawn)
score += CENTER_PAWN_BLOCK;
}
}
switch(piece.Type())
{
case Piece::Bishop:
{
{
for (int j = 0; j < 4; j++)
{
const byte *data = BishopSquares[sq] + (j*8);
for (;;)
{
byte b = *data;
if (b == 255)
break;
data++;
Piece piece = board[b];
if (piece.IsEmpty())
mobl++;
else
break;
}
}
}
if (mobl==0)
score2 += BLOCKED_BISHOP;
else if (mobl == 1)
score2 += LOW_BISHOP_MOBILITY;
else if (mobl > BMOBLTHRESH)
score2 += (mobl / BMOBLTHRESH)*BISHOP_MOBILITY;
if (rank == file)
score2 += LONG_DIAG;
if (back && !endgame)
score += BISHOP_BACK;
}
break;
case Piece::Knight:
if (back && !endgame)
score += KNIGHT_BACK;
if (file == 1 || file == 8)
score2 += KNIGHT_ON_RIM;
if (!endgame)
{
const byte *data = KnightSquares[(int)sq];
int j = 0;
while (j < 8 && data[j] != 255)
{
Square dest(data[j]);
if (board[dest].IsEmpty() &&
board.pawn_attacks(dest,oside) ==0)
score += KNIGHT_MOBILITY;
++j;
}
}
break;
case Piece::Queen:
have_queen = True;
queen_back = back;
break;
case Piece::Rook:
if (back && !endgame)
{
mobl = 0;
Square sq2(sq);
while (sq2.File() < 8)
{
++sq2;
if (board[sq2].IsEmpty())
mobl++;
else
break;
}
sq2 = sq;
while (sq2.File() > 1)
{
--sq2;
if (board[sq2].IsEmpty())
mobl++;
else
break;
}
if (mobl < 3)
score2 += LOW_ROOK_MOBILITY;
}
if (rank == 7)
score2 += ROOK_ON_7TH_RANK;
if (board.PFileCount(file-1,side)==0)
score2 += ROOK_ON_HALF_OPEN_FILE;
if (board.PFileCount(file-1,oside)==0)
{
score2 += ROOK_ON_OPEN_FILE;
const int rr = board.RFileCount(file-1,side);
if (rr>=2)
score2 += DOUBLED_ROOKS/2;
}
default:
break;
}
}
}
}
if (!endgame && have_queen && !queen_back)
{
if (score == 0 &&
(board.CastleStatus(side) == Board::CastledKSide ||
board.CastleStatus(side) == Board::CastledQSide))
score += QUEEN_DEVELOP;
else // premature development of queen
score += QUEEN_OUT;
}
if (endgame)
{
Square kp(board.KingPos(side));
if (board.Side() != side)
{
for (int j = 0; j < 4; j++)
{
const byte *data = RookSquares[kp] + (j*8);
if (*data == 255)
continue;
else
data++;
if (*data != 255 && board[*data].Type() == Piece::King)
{
score += OPPOSITION;
break;
}
}
}
if (mopping_up(board,side))
{
// Encourage bringing our king close to opposing king:
Square oppkp(board.KingPos(oside));
const int opprank = oppkp.Rank(White);
const int oppfile = oppkp.File();
const int ourrank = kp.Rank(White);
const int ourfile = kp.File();
int dist = Util::Abs(oppfile - ourfile) +
Util::Abs(ourrank - opprank);
score += (5-dist)*KING_DISTANCE;
if ((unsigned)board.getMaterial(side).infobits() == 0x8048)
{
// KBNK endgame, special case. This code is currently
// insufficient to allow the stronger side to win, but
// it does help the weaker side put up a good defense.
ColorType bishopColor;
for (int i = 0; i < 16; i++)
{
Square sq(board.PiecePos(board.Side(),i));
if ( sq != Square::Invalid())
if (board[sq].Type() == Piece::Bishop)
{
bishopColor = sq.Color();
break;
}
}
// encourage getting the king to the "right" corner:
Square evalsq;
if (bishopColor == White)
{
evalsq = Square(9-opprank, oppfile, White);
}
else
{
evalsq = oppkp;
}
score += KBNKScores[evalsq];
}
else
{
// Encourage putting the king on the edge of the board:
if (oppkp.OnEdge())
score += KING_ON_EDGE;
if (oppfile == 1 || oppfile == 8)
{
if (opprank == 1 || opprank == 8)
score += KING_IN_CORNER;
}
// Encourage restricting opposing king's mobility:
const byte *data = KingSquares[(int)oppkp];
score -= 8*KING_CAN_MOVE;
for (i = 0; i <8 && *data != 255 ;i++)
{
Square sq(*data++);
if (board.num_attacks(sq,side) == 0)
score += KING_CAN_MOVE;
}
}
}
else if ((unsigned)board.getMaterial(side).infobits() == 0x8001 &&
(unsigned)board.getMaterial(oside).king_only())
{
// KPK endgame
Square pawnpos;
for (int i = 0; i < 16; i++)
{
Square sq(board.PiecePos(side,i));
if (!sq.IsInvalid() && board[sq].Type() == Piece::Pawn)
{
pawnpos = sq;
break;
}
}
Square oppkp(board.KingPos(oside));
Square kp(board.KingPos(side));
Boolean uncatchable = False;
if (board.Side() == side)
{
uncatchable =
(pawnpos.Rank(side) >= oppkp.Rank(side) &&
Util::Abs(pawnpos.File() - oppkp.File()) >=
8 - pawnpos.Rank(side));
}
else
{
uncatchable =
(pawnpos.Rank(side) >= oppkp.Rank(side) + 1 &&
Util::Abs(pawnpos.File() - oppkp.File()) >=
9 - pawnpos.Rank(side));
}
if (uncatchable)
score += UNCATCHABLE_PAWN;
else
{
// we can't just push the pawn.
int rank = pawnpos.Rank(side);
int file_dist = Util::Abs(pawnpos.File() - kp.File());
if (kp.Rank(side) > rank && file_dist <= 1)
{
score += KING_AHEAD_OF_PAWN;
if (rank < 6 && file_dist == 0)
score += KING_SAME_FILE;
}
else
score -= PASSED_PAWN[rank-1]/2;
// also encourage staying near pawn
score += 10 + DISTANCE_FROM_PAWN*distance(kp,pawnpos);
}
}
else
{
// This code is VERY crude .. it helps (a little) in king and
// pawn endgames, but is pretty useless otherwise ... Lots more
// work to do here.
score += KingCenterScores[kp];
if (kp.Rank(side) > 4)
score += ADVANCED_KING;
// bonus for king near pawns
const byte *data = KingSquares[(int)kp];
const Boolean king_only
= (unsigned)board.getMaterial(side).king_only();
for (i = 0; i <8 && *data != 255 ;i++)
{
Square sq(*data++);
if (board[sq].Type() == Piece::Pawn)
{
score += KING_NEAR_PAWN;
if (king_only)
{
int file_dist = Util::Abs(kp.File() - sq.File());
int rank_dist = Util::Abs(kp.Rank(side) - sq.Rank(side));
score += 20 + KING_PAWN_DISTANCE*(file_dist + rank_dist);
if (kp.Rank(oside) >
sq.Rank(oside))
score += OPP_KING_AHEAD_OF_PAWN;
}
}
}
}
}
return score + score2;
}
Boolean search( const Board &board, const Square &sq,
const int start, const int limit, const ColorType side_to_search,
const ColorType side )
{
// search rows adjacent to "sq" for presence of a pawn of color
// 'side_to_search'.
// search covers ranks "start" to "limit" (from the perspective of
// 'side'). The function value is set True if a pawn is found.
const Piece apawn(Piece::Pawn,side_to_search);
int dir, incr;
if (limit > start)
{
dir = 1;
incr = RankIncr;
}
else
{
dir = -1;
incr = -RankIncr;
}
if (side == White) incr = -incr;
const int file = sq.File();
Square sq2(file,start,side);
for (int rank = start; rank != limit; rank += dir)
{
if (((file != 8) && board[sq2 + 1] == apawn) ||
((file != 1) && board[sq2 - 1] == apawn))
return True;
sq2 += incr;
}
return False;
}
int PawnStructure( const Board &board, const ColorType side )
{
int score = 0;
const Piece our_pawn( Piece::Pawn, side );
for (int k = 0; k < 16; k++)
{
Square sq(board.PiecePos(side,k));
if (!sq.IsInvalid())
{
Piece piece = board[sq];
if (piece.Type() == Piece::Pawn)
{
int rank = sq.Rank(side);
int file = sq.File();
Boolean backward = False;
Boolean passed = False;
Boolean isolated;
if (rank == 7)
score += PAWN_ON_7TH_RANK;
if (board.PFileCount(file-1,OppositeColor(side))==0)
{
backward = !search(board,sq,rank,1,side,side);
passed = !search(board,sq,rank+1,8,OppositeColor(side),side);
}
isolated = Boolean(board.PFileCount(file-1,side)==0 &&
board.PFileCount(file+1,side)==0);
if (backward && !isolated)
score += BACKWARD_PAWN;
else if (isolated)
{
if (file>=3 && file<=6)
score += CENTRAL_ISOLANI;
else
score += ISOLANI;
}
if (!isolated && rank > 2)
{
Square sq2 = sq + ((Direction[side] >0) ?
-RankIncr : +RankIncr);
if (!(file != 1 && board[sq2 - 1] == our_pawn) &&
!(file != 8 && board[sq2 + 1] == our_pawn))
score += UNSUPPORTED_PAWN;
}
if (passed)
{
score += PASSED_PAWN[rank-1];
if (file ==1 || file == 8)
score += RIM_PASSED_PAWN;
for (int j=rank+1;j<9;j++)
{
Square sq2(file,j,side);
Piece piece2 = board[sq2];
if (!piece2.IsEmpty() &&
(piece2.Color() == OppositeColor(side)))
{
// blocked passed pawn
int hit = PASSED_PAWN[rank-1]/3;
// double score if we block the passed pawn
// by occupying the square in front of it:
if (j==rank+1)
score -= 2*hit;
else
score -= hit;
break;
}
}
if (endgame)
{
Square oppkp(board.KingPos(OppositeColor(side)));
score += OPP_KING_DISTANCE_FROM_PP*
distance(oppkp,sq);
if (oppkp.Rank(side) > sq.Rank(side))
score += OPP_KING_AHEAD_OF_PP;
}
for (j=rank-1;j>0;j--)
{
Square sq3(file,j,side);
Piece piece3 = board[sq3];
if (!piece3.IsEmpty())
{
if (piece3.Color() == side)
{
if (piece3.Type() == Piece::Rook || piece3.Type()
== Piece::Queen)
{
score += ROOK_BEHIND_PP;
break;
}
}
else
break;
}
}
}
if (rank >3 && file != 8 && board[sq+1] == piece)
score += PAWN_DUO;
}
}
}
for (int i = 0; i < 8; i++)
{
const int pr = board.PFileCount(i,side);
if (pr == 2)
score += DOUBLED_PAWNS;
else if (pr > 2)
score += TRIPLED_PAWNS;
}
return score;
}
int Castling( const Board &board, const ColorType side )
{
int score = 0;
int i;
int atcks = 0;
Square kp(board.KingPos(side));
switch (board.CastleStatus(side))
{
case Board::CanCastleEitherSide:
score += CAN_CASTLE;
for (i = -1; i >= -2; --i)
if (board.num_attacks(kp+i,OppositeColor(side)))
{
atcks++;
break;
}
for (i = 1; i <= 2; ++i)
if (board.num_attacks(kp+i,OppositeColor(side)))
{
atcks++;
break;
}
score += (ATTACK_PREVENTS_CASTLING)*atcks;
break;
case Board::CanCastleKSide:
score += CANT_CASTLE_Q_SIDE;
for (i = 1; i <= 2; ++i)
if (board.num_attacks(kp+i,OppositeColor(side)))
{
atcks++;
break;
}
if (atcks)
score += (ATTACK_PREVENTS_CASTLING)*atcks;
break;
case Board::CanCastleQSide:
score += CANT_CASTLE_K_SIDE;
for (i = -1; i >= -2; --i)
if (board.num_attacks(kp+i,OppositeColor(side)))
{
atcks++;
break;
}
if (atcks)
score += ATTACK_PREVENTS_CASTLING;
break;
case Board::CastledKSide:
score += KCASTLE; break;
case Board::CastledQSide:
score += QCASTLE; break;
case Board::CantCastleEitherSide:
score += CANT_CASTLE; break;
}
return score;
}
int KingSafety( const Board &board, const ColorType side)
{
int score = 0;
if ((side == board.Side()) && board.CheckStatus() == Board::InCheck)
score += CHECK;
Square kp(board.KingPos(side));
if (!endgame || mopping_up(board,OppositeColor(side)))
{
const byte *data = KingSquares[(int)kp];
for (int i = 0; i <8 && *data != 255 ;i++)
{
if (board.num_attacks(*data++,OppositeColor(side)) >0)
score += ATTACK_NEAR_KING;
}
}
if (!endgame)
{
if (kp.Rank(side) != 8)
score += KING_OFF_BACK_RANK;
int dir = (side == White ? -RankIncr : RankIncr);
Piece my_pawn(Piece::Pawn,side);
if (kp.File() != 1)
{
Square sq(kp-1);
Square pawnsq(sq+dir);
if (pawnsq.OnBoard() &&
board[pawnsq] == my_pawn)
score += KING_PAWN_COVER;
else if (board.PFileCount(sq.File()-1,side) == 0 &&
board.PFileCount(sq.File()-1,OppositeColor(side)) == 0)
score += KING_NEAR_OPEN_FILE;
}
Square pawnsq(kp+dir);
if (pawnsq.OnBoard() &&
board[pawnsq] == my_pawn)
score += KING_PAWN_COVER;
else if (board.PFileCount(kp.File()-1,side) == 0 &&
board.PFileCount(kp.File()-1,OppositeColor(side)) == 0)
score += KING_NEAR_OPEN_FILE;
if (kp.File() != 8)
{
Square sq(kp+1);
Square pawnsq(sq+dir);
if (pawnsq.OnBoard() &&
board[pawnsq] == my_pawn)
score += KING_PAWN_COVER;
else if (board.PFileCount(sq.File()-1,side) == 0 &&
board.PFileCount(sq.File()-1,OppositeColor(side)) == 0)
score += KING_NEAR_OPEN_FILE;
}
const int kpfile = kp.File();
for (int j=0;j<16;j++)
{
Square sq(board.PiecePos(board.OppositeSide(),j));
if (!sq.IsInvalid())
{
Piece::PieceType p = board[sq].Type();
if (p==Piece::Rook || p == Piece::Queen)
{
if (Util::Abs(kpfile - sq.File()) <= 1)
{
score += DANGER_ON_FILE;
break;
}
}
}
}
}
return score;
}
Boolean Scoring::check_en_prise( const Board &board, const Square sq,
const Piece p)
{
Boolean en_prise = False;
if (p.Type() == Piece::Pawn ||
board.num_attacks(sq,board.OppositeSide()) == 0)
{
return False;
}
if (board.pawn_attacks(sq,board.OppositeSide()) > 0)
{
Scoring::pawn_threats = en_prise = True;
}
else if (board.num_attacks(sq,board.Side()) == 0)
en_prise = True;
else
{
const Attack_Entry &entr =
board.get_attacks(sq,board.OppositeSide());
if (Piece::Value(entr.min_attacker()) < p.Value())
en_prise = True;
}
return en_prise;
}
int Scoring::threat_score( const Board &board, const ColorType side )
{
int score = 0;
en_prise = 0;
trapped = False;
pawn_threats = False;
for (int i = 0; i < 16; i++)
{
Square sq(board.PiecePos(side,i));
if (!sq.IsInvalid())
{
Piece piece(board[sq]);
if (check_en_prise(board,sq,piece))
{
// piece is apparently en prise
score += EN_PRISE;
en_prise++;
if (!trapped)
{
trapped = True;
Piece pinnedByPiece;
Square pinnedBySquare;
int dir;
Boolean pinned =
Bearing::Pinned(board,sq,pinnedByPiece,
pinnedBySquare,dir);
// Treat a pinned piece same as a trapped one:
if (pinned)
continue;
Square squares[Bearing::MaxBearSq];
unsigned n = Bearing::BearSq(board,sq,squares);
for (unsigned j = 0; j < n; j++)
{
Square dest(squares[j]);
if (!check_en_prise(board,dest,piece))
{
trapped = False;
break;
}
} // for
}
}
}
}
if (en_prise > 1)
score += TWO_EN_PRISE;
if (trapped)
score += PIECE_TRAPPED;
return score;
}
int Scoring::evalu8( const Board &board )
{
int score = 0;
endgame = in_endgame(board,board.Side());
score += MaterialScore(board,board.Side())
+ Center(board,board.Side())
- Center(board,board.OppositeSide())
+ Development(board,board.Side())
- Development(board,board.OppositeSide())
+ Castling(board,board.Side())
- Castling(board,board.OppositeSide())
+ PawnStructure(board,board.Side())
- PawnStructure(board,board.OppositeSide())
+ KingSafety(board,board.Side())
- KingSafety(board,board.OppositeSide())
+ threat_score(board,board.Side());
return score;
}
int Scoring::positional_score( const Board &board )
// returns a positional score
{
int score = 0;
endgame = in_endgame(board,board.Side());
score += Center(board,board.Side())
- Center(board,board.OppositeSide())
+ Development(board,board.Side())
- Development(board,board.OppositeSide())
+ Castling(board,board.Side())
- Castling(board,board.OppositeSide())
+ PawnStructure(board,board.Side())
- PawnStructure(board,board.OppositeSide())
+ KingSafety(board,board.Side())
- KingSafety(board,board.OppositeSide())
+ threat_score(board,board.Side());
return score;
}
int Scoring::positional_score( const Board &board, Scores &scores,
Scores &opp_scores )
// returns a positional score
{
endgame = in_endgame(board,board.Side());
scores.center = Center(board,board.Side());
opp_scores.center = Center(board,board.OppositeSide());
scores.development =
Development(board,board.Side());
opp_scores.development =
Development(board,board.OppositeSide());
scores.castling =
Castling(board,board.Side());
opp_scores.castling =
Castling(board,board.OppositeSide());
scores.pawn_structure =
PawnStructure(board,board.Side());
opp_scores.pawn_structure =
PawnStructure(board,board.OppositeSide());
scores.king_safety =
KingSafety(board,board.Side());
opp_scores.king_safety =
KingSafety(board,board.OppositeSide());
scores.threats =
threat_score(board,board.Side());
opp_scores.threats = 0;
return scores.center + scores.development + scores.castling +
scores.pawn_structure + scores.king_safety + scores.threats
- (opp_scores.center + opp_scores.development +
opp_scores.castling + opp_scores.pawn_structure +
opp_scores.king_safety + opp_scores.threats);
}
int Scoring::material_score( const Board &board )
// returns a material score
{
return MaterialScore(board,board.Side());
}